﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Mono.Cecil.Metadata;
using Mono.Cecil.PE;

namespace Mono.Cecil.Cil
{
	// Token: 0x0200012F RID: 303
	public sealed class PortablePdbWriter : ISymbolWriter, IDisposable
	{
		// Token: 0x170002F4 RID: 756
		// (get) Token: 0x06000B7F RID: 2943 RVA: 0x00034040 File Offset: 0x00032240
		private bool IsEmbedded
		{
			get
			{
				return this.writer == null;
			}
		}

		// Token: 0x06000B80 RID: 2944 RVA: 0x0003405C File Offset: 0x0003225C
		internal PortablePdbWriter(MetadataBuilder pdb_metadata, ModuleDefinition module)
		{
			this.pdb_metadata = pdb_metadata;
			this.module = module;
			this.module_metadata = module.metadata_builder;
			bool flag = this.module_metadata != pdb_metadata;
			if (flag)
			{
				this.pdb_metadata.metadata_builder = this.module_metadata;
			}
			pdb_metadata.AddCustomDebugInformations(module);
		}

		// Token: 0x06000B81 RID: 2945 RVA: 0x00006151 File Offset: 0x00004351
		internal PortablePdbWriter(MetadataBuilder pdb_metadata, ModuleDefinition module, ImageWriter writer, Disposable<Stream> final_stream) : this(pdb_metadata, module)
		{
			this.writer = writer;
			this.final_stream = final_stream;
		}

		// Token: 0x06000B82 RID: 2946 RVA: 0x000340B4 File Offset: 0x000322B4
		public ISymbolReaderProvider GetReaderProvider()
		{
			return new PortablePdbReaderProvider();
		}

		// Token: 0x06000B83 RID: 2947 RVA: 0x0000616C File Offset: 0x0000436C
		public void Write(MethodDebugInformation info)
		{
			this.CheckMethodDebugInformationTable();
			this.pdb_metadata.AddMethodDebugInformation(info);
		}

		// Token: 0x06000B84 RID: 2948 RVA: 0x000340CC File Offset: 0x000322CC
		public void Write()
		{
			bool isEmbedded = this.IsEmbedded;
			if (!isEmbedded)
			{
				this.WritePdbFile();
				bool flag = this.final_stream.value != null;
				if (flag)
				{
					this.writer.BaseStream.Seek(0L, SeekOrigin.Begin);
					byte[] buffer = new byte[8192];
					CryptoService.CopyStreamChunk(this.writer.BaseStream, this.final_stream.value, buffer, (int)this.writer.BaseStream.Length);
				}
			}
		}

		// Token: 0x06000B85 RID: 2949 RVA: 0x00034150 File Offset: 0x00032350
		public ImageDebugHeader GetDebugHeader()
		{
			bool isEmbedded = this.IsEmbedded;
			ImageDebugHeader result;
			if (isEmbedded)
			{
				result = new ImageDebugHeader();
			}
			else
			{
				ImageDebugDirectory directory = new ImageDebugDirectory
				{
					MajorVersion = 256,
					MinorVersion = 20557,
					Type = ImageDebugType.CodeView,
					TimeDateStamp = (int)this.pdb_id_stamp
				};
				ByteBuffer byteBuffer = new ByteBuffer();
				byteBuffer.WriteUInt32(1396986706U);
				byteBuffer.WriteBytes(this.pdb_id_guid.ToByteArray());
				byteBuffer.WriteUInt32(1U);
				string text = this.writer.BaseStream.GetFileName();
				bool flag = string.IsNullOrEmpty(text);
				if (flag)
				{
					text = this.module.Assembly.Name.Name + ".pdb";
				}
				byteBuffer.WriteBytes(Encoding.UTF8.GetBytes(text));
				byteBuffer.WriteByte(0);
				byte[] array = new byte[byteBuffer.length];
				Buffer.BlockCopy(byteBuffer.buffer, 0, array, 0, byteBuffer.length);
				directory.SizeOfData = array.Length;
				ImageDebugHeaderEntry imageDebugHeaderEntry = new ImageDebugHeaderEntry(directory, array);
				ImageDebugDirectory directory2 = new ImageDebugDirectory
				{
					MajorVersion = 1,
					MinorVersion = 0,
					Type = ImageDebugType.PdbChecksum,
					TimeDateStamp = 0
				};
				ByteBuffer byteBuffer2 = new ByteBuffer();
				byteBuffer2.WriteBytes(Encoding.UTF8.GetBytes("SHA256"));
				byteBuffer2.WriteByte(0);
				byteBuffer2.WriteBytes(this.pdb_checksum);
				byte[] array2 = new byte[byteBuffer2.length];
				Buffer.BlockCopy(byteBuffer2.buffer, 0, array2, 0, byteBuffer2.length);
				directory2.SizeOfData = array2.Length;
				ImageDebugHeaderEntry imageDebugHeaderEntry2 = new ImageDebugHeaderEntry(directory2, array2);
				result = new ImageDebugHeader(new ImageDebugHeaderEntry[]
				{
					imageDebugHeaderEntry,
					imageDebugHeaderEntry2
				});
			}
			return result;
		}

		// Token: 0x06000B86 RID: 2950 RVA: 0x00034330 File Offset: 0x00032530
		private void CheckMethodDebugInformationTable()
		{
			MethodDebugInformationTable table = this.pdb_metadata.table_heap.GetTable<MethodDebugInformationTable>(Table.MethodDebugInformation);
			bool flag = table.length > 0;
			if (!flag)
			{
				table.rows = new Row<uint, uint>[this.module_metadata.method_rid - 1U];
				table.length = table.rows.Length;
			}
		}

		// Token: 0x06000B87 RID: 2951 RVA: 0x00034388 File Offset: 0x00032588
		public void Dispose()
		{
			this.writer.stream.Dispose();
			this.final_stream.Dispose();
		}

		// Token: 0x06000B88 RID: 2952 RVA: 0x000343BC File Offset: 0x000325BC
		private void WritePdbFile()
		{
			this.WritePdbHeap();
			this.WriteTableHeap();
			this.writer.BuildMetadataTextMap();
			this.writer.WriteMetadataHeader();
			this.writer.WriteMetadata();
			this.writer.Flush();
			this.ComputeChecksumAndPdbId();
			this.WritePdbId();
		}

		// Token: 0x06000B89 RID: 2953 RVA: 0x00034418 File Offset: 0x00032618
		private void WritePdbHeap()
		{
			PdbHeapBuffer pdb_heap = this.pdb_metadata.pdb_heap;
			pdb_heap.WriteBytes(20);
			pdb_heap.WriteUInt32(this.module_metadata.entry_point.ToUInt32());
			TableHeapBuffer table_heap = this.module_metadata.table_heap;
			MetadataTable[] tables = table_heap.tables;
			ulong num = 0UL;
			for (int i = 0; i < tables.Length; i++)
			{
				bool flag = tables[i] == null || tables[i].Length == 0;
				if (!flag)
				{
					num |= 1UL << i;
				}
			}
			pdb_heap.WriteUInt64(num);
			for (int j = 0; j < tables.Length; j++)
			{
				bool flag2 = tables[j] == null || tables[j].Length == 0;
				if (!flag2)
				{
					pdb_heap.WriteUInt32((uint)tables[j].Length);
				}
			}
		}

		// Token: 0x06000B8A RID: 2954 RVA: 0x000344FC File Offset: 0x000326FC
		private void WriteTableHeap()
		{
			this.pdb_metadata.table_heap.string_offsets = this.pdb_metadata.string_heap.WriteStrings();
			this.pdb_metadata.table_heap.ComputeTableInformations();
			this.pdb_metadata.table_heap.WriteTableHeap();
		}

		// Token: 0x06000B8B RID: 2955 RVA: 0x0003454C File Offset: 0x0003274C
		private void ComputeChecksumAndPdbId()
		{
			byte[] buffer = new byte[8192];
			this.writer.BaseStream.Seek(0L, SeekOrigin.Begin);
			SHA256 sha = SHA256.Create();
			using (CryptoStream cryptoStream = new CryptoStream(Stream.Null, sha, CryptoStreamMode.Write))
			{
				CryptoService.CopyStreamChunk(this.writer.BaseStream, cryptoStream, buffer, (int)this.writer.BaseStream.Length);
			}
			this.pdb_checksum = sha.Hash;
			ByteBuffer byteBuffer = new ByteBuffer(this.pdb_checksum);
			this.pdb_id_guid = new Guid(byteBuffer.ReadBytes(16));
			this.pdb_id_stamp = byteBuffer.ReadUInt32();
		}

		// Token: 0x06000B8C RID: 2956 RVA: 0x00006183 File Offset: 0x00004383
		private void WritePdbId()
		{
			this.writer.MoveToRVA(TextSegment.PdbHeap);
			this.writer.WriteBytes(this.pdb_id_guid.ToByteArray());
			this.writer.WriteUInt32(this.pdb_id_stamp);
		}

		// Token: 0x04000713 RID: 1811
		private readonly MetadataBuilder pdb_metadata;

		// Token: 0x04000714 RID: 1812
		private readonly ModuleDefinition module;

		// Token: 0x04000715 RID: 1813
		private readonly ImageWriter writer;

		// Token: 0x04000716 RID: 1814
		private readonly Disposable<Stream> final_stream;

		// Token: 0x04000717 RID: 1815
		private MetadataBuilder module_metadata;

		// Token: 0x04000718 RID: 1816
		internal byte[] pdb_checksum;

		// Token: 0x04000719 RID: 1817
		internal Guid pdb_id_guid;

		// Token: 0x0400071A RID: 1818
		internal uint pdb_id_stamp;
	}
}
